﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace PronosGestor
{
    public class PronosGestor
    {
        //private const string _path = @"\\smbadoc04\PrjFonc\Domaine\AD_E-Pleiade\Outils\e-Pronos\2012-2013\";
        private const string _path = @"F:\2012-2013\";

        //private StreamReader config = new StreamReader("Config.ini", Encoding.GetEncoding(1252));

        private StreamReader sRJoueurs = new StreamReader(_path + "ListeParticipants.txt", Encoding.GetEncoding(1252));
        private StreamReader sREquipes = new StreamReader(_path + "ListeEquipes.txt", Encoding.GetEncoding(1252));
        private StreamWriter log = new StreamWriter(_path + "log.txt", false, Encoding.GetEncoding(1252));
        private StreamReader stats = new StreamReader(_path + "stats.txt", Encoding.GetEncoding(1252));
        private StreamReader statsPronos = new StreamReader(_path + "stats_pronos.txt", Encoding.GetEncoding(1252));

        // Traitement d'une journée
        private StreamReader pronosJournee;
        private StreamReader matchs;
        private StreamReader resultats;
        private StreamWriter logPronos;

        private List<Participant> joueurs = new List<Participant>();
        private List<KeyValuePair<string, double[]>> listeMatchs = new List<KeyValuePair<string, double[]>>();
        private List<KeyValuePair<int, double[]>> resultatsMatchs = new List<KeyValuePair<int, double[]>>();
        private List<KeyValuePair<string, double[]>> ficheResultatsJoueurs = new List<KeyValuePair<string, double[]>>();

        private bool existeResultats = false;

        public void Init()
        {

            // Alimentation des équipes
            while (!sREquipes.EndOfStream)
            {
                //equipes.Add(new Equipe(sREquipes.ReadLine()));
            }

            // Alimentation des joueurs
            while (!sRJoueurs.EndOfStream)
            {

                string[] joueurCorrespondance = sRJoueurs.ReadLine().Split(';');
                //joueurs.Add(new Participant(joueurCorrespondance[0].ToString(), equipes.Find(x => x.nom == joueurCorrespondance[1])));
            }

            // Ecriture des infos dans la log

            log.WriteLine("Liste des équipes :");

            //foreach (Equipe equipe in equipes)
            //{
            //    log.WriteLine(" ->" + equipe.nom);
            //}

            log.WriteLine("");
            log.WriteLine("Liste des joueurs : ");

            foreach (Participant part in joueurs)
            {
                log.WriteLine(" -> Nom du joueur : " + part.nom + " | Equipe favorite : " + part.equipePreferee);
            }

            sREquipes.Close();
            sRJoueurs.Close();
            log.Close();
        }

        public void StatistiquesEcartsButsSaison()
        {
            string line = "";
            string[] scores = new string[2];
            double nbScores = 0;
            double domicile = 0;
            double exterieur = 0;

            double nb1 = 0;
            double nb2 = 0;
            double nbN = 0;
            double ecart0 = 0;
            double ecart1 = 0;
            double ecart2 = 0;
            double ecart3 = 0;
            double ecart4 = 0;
            double ecart5Plus = 0;

            while (!stats.EndOfStream)
            {
                line = stats.ReadLine();
                scores = line.Split(';');
                domicile = Convert.ToDouble(scores[0]);
                exterieur = Convert.ToDouble(scores[1]);
                nbScores++;

                if (domicile > exterieur)
                {
                    nb1++;
                }
                else if (domicile == exterieur)
                {
                    nbN++;
                }
                else
                    nb2++;

                if (Math.Abs(domicile - exterieur) == 0)
                {
                    ecart0++;
                }
                else if (Math.Abs(domicile - exterieur) == 1)
                {
                    ecart1++;
                }
                else if (Math.Abs(domicile - exterieur) == 2)
                {
                    ecart2++;
                }
                else if (Math.Abs(domicile - exterieur) == 3)
                {
                    ecart3++;
                }
                else if (Math.Abs(domicile - exterieur) == 4)
                {
                    ecart4++;
                }
                else
                {
                    ecart5Plus++;
                }
            }

            // Analyse des résultats
            log.WriteLine("Nombre de scores : " + nbScores.ToString());

            log.WriteLine("% victoires à domicile : " + (nb1 / nbScores * 100) + " - nombre exact : " + nb1);
            log.WriteLine("% victoires à l'extérieur : " + (nb2 / nbScores * 100) + " - nombre exact : " + nb2);
            log.WriteLine("% nuls : " + (nbN / nbScores * 100) + " - nombre exact : " + nbN);

            log.WriteLine("% écarts de 0 but : " + (ecart0 / nbScores * 100) + " - nombre exact : " + ecart0);
            log.WriteLine("% écarts de 1 but : " + (ecart1 / nbScores * 100) + " - nombre exact : " + ecart1);
            log.WriteLine("% écarts de 2 buts : " + (ecart2 / nbScores * 100) + " - nombre exact : " + ecart2);
            log.WriteLine("% écarts de 3 buts : " + (ecart3 / nbScores * 100) + " - nombre exact : " + ecart3);
            log.WriteLine("% écarts de 4 buts : " + (ecart4 / nbScores * 100) + " - nombre exact : " + ecart4);
            log.WriteLine("% écarts de 5 buts ou plus : " + (ecart5Plus / nbScores * 100) + " - nombre exact : " + ecart5Plus);

            sREquipes.Close();
            sRJoueurs.Close();
            log.Close();
        }

        public void StatistiquesEcartsButsPronos()
        {
            char[] scores = new char[2];
            double nbScores = 0;
            double domicile = 0;
            double exterieur = 0;

            double nb1 = 0;
            double nb2 = 0;
            double nbN = 0;
            double ecart0 = 0;
            double ecart1 = 0;
            double ecart2 = 0;
            double ecart3 = 0;
            double ecart4 = 0;
            double ecart5Plus = 0;

            while (!statsPronos.EndOfStream)
            {
                scores = statsPronos.ReadLine().ToCharArray();
                if (scores.Length > 0)
                {
                    domicile = Convert.ToDouble(Convert.ToString(scores[0]));
                    exterieur = Convert.ToDouble(Convert.ToString(scores[1]));
                    nbScores++;

                    if (domicile > exterieur)
                    {
                        nb1++;
                    }
                    else if (domicile == exterieur)
                    {
                        nbN++;
                    }
                    else
                        nb2++;

                    if (Math.Abs(domicile - exterieur) == 0)
                    {
                        ecart0++;
                    }
                    else if (Math.Abs(domicile - exterieur) == 1)
                    {
                        ecart1++;
                    }
                    else if (Math.Abs(domicile - exterieur) == 2)
                    {
                        ecart2++;
                    }
                    else if (Math.Abs(domicile - exterieur) == 3)
                    {
                        ecart3++;
                    }
                    else if (Math.Abs(domicile - exterieur) == 4)
                    {
                        ecart4++;
                    }
                    else
                    {
                        ecart5Plus++;
                    }
                }
            }

            // Analyse des résultats
            log.WriteLine("*** PRONOSTICS ***");
            log.WriteLine("Nombre de scores : " + nbScores.ToString());

            log.WriteLine("% victoires à domicile : " + (nb1 / nbScores * 100) + " - nombre exact : " + nb1);
            log.WriteLine("% victoires à l'extérieur : " + (nb2 / nbScores * 100) + " - nombre exact : " + nb2);
            log.WriteLine("% nuls : " + (nbN / nbScores * 100) + " - nombre exact : " + nbN);

            log.WriteLine("% écarts de 0 but : " + (ecart0 / nbScores * 100) + " - nombre exact : " + ecart0);
            log.WriteLine("% écarts de 1 but : " + (ecart1 / nbScores * 100) + " - nombre exact : " + ecart1);
            log.WriteLine("% écarts de 2 buts : " + (ecart2 / nbScores * 100) + " - nombre exact : " + ecart2);
            log.WriteLine("% écarts de 3 buts : " + (ecart3 / nbScores * 100) + " - nombre exact : " + ecart3);
            log.WriteLine("% écarts de 4 buts : " + (ecart4 / nbScores * 100) + " - nombre exact : " + ecart4);
            log.WriteLine("% écarts de 5 buts ou plus : " + (ecart5Plus / nbScores * 100) + " - nombre exact : " + ecart5Plus);

            sREquipes.Close();
            sRJoueurs.Close();
            log.Close();
        }

        /// <summary>
        /// Traitement d'une journée de pronos.
        /// -1 correspond à un match non pronostiqué
        /// </summary>
        public void TraiterJourneePronostics(string indexJournee)
        {
            // Pronos
            int compteurMatchs = 0;
            string line;
            string[] scores;
            double nbScores = 0;
            double domicile = 0;
            double exterieur = 0;

            // Stats pronos
            double nb1 = 0;
            double nb2 = 0;
            double nbN = 0;
            double ecart0 = 0;
            double ecart1 = 0;
            double ecart2 = 0;
            double ecart3 = 0;
            double ecart4 = 0;
            double ecart5Plus = 0;

            // Résultats
            int indexMatchs = 0;
            double pointsJoueurActu = 0;
            double gainBrut = 0;

            // Récupération des pronos et des matchs
            pronosJournee = new StreamReader(_path + @"\Journée " + indexJournee + @"\JourneeProno.txt", Encoding.GetEncoding(1252));
            matchs = new StreamReader(_path + @"\Journée " + indexJournee + @"\Matchs.txt", Encoding.GetEncoding(1252));
            resultats = new StreamReader(_path + @"\Journée " + indexJournee + @"\Résultats.txt", Encoding.GetEncoding(1252));
            logPronos = new StreamWriter(_path + @"\Journée " + indexJournee + @"\Log.txt", false, Encoding.GetEncoding(1252));

            // Récupération des matchs :
            while (!matchs.EndOfStream)
            {
                listeMatchs.Add(new KeyValuePair<string, double[]>(matchs.ReadLine(), new double[3]));
            }

            // Récupération des résultats :
            if (resultats.ReadLine().Contains("OK"))
            {
                while (!resultats.EndOfStream)
                {
                    string[] resultat = resultats.ReadLine().Split(';');
                    string equipeDomicile = resultat[0];
                    double scoreDomicile = -1;
                    double scoreExterireur = -1;

                    if (resultat[1] != "")
                    {
                        existeResultats = true;
                        scoreDomicile = Convert.ToDouble(resultat[1]);
                    }
                    if (resultat[2] != "") scoreExterireur = Convert.ToDouble(resultat[2]);
                    string equipeExterieur = resultat[3];

                    // Ajout du match dans la liste
                    double[] score = new double[2];
                    score[0] = scoreDomicile;
                    score[1] = scoreExterireur;

                    resultatsMatchs.Add(new KeyValuePair<int, double[]>(indexMatchs, score));
                    indexMatchs++;
                }
            }

            // Récupération des pronostics
            while (!pronosJournee.EndOfStream)
            {
                line = pronosJournee.ReadLine();
                scores = line.Split(';');

                nbScores = 0;
                domicile = 0;
                exterieur = 0;

                nb1 = 0;
                nb2 = 0;
                nbN = 0;
                ecart0 = 0;
                ecart1 = 0;
                ecart2 = 0;
                ecart3 = 0;
                ecart4 = 0;
                ecart5Plus = 0;

                // Pour chaque pronostiqueur
                for (int i = 0; i < scores.Length; i++)
                {
                    domicile = Convert.ToInt32(scores[i].Split('.')[0]);
                    exterieur = Convert.ToInt32(scores[i].Split('.')[1]);

                    if (domicile > -1)
                    {
                        nbScores++;

                        if (domicile > exterieur)
                        {
                            nb1++;
                        }
                        else if (domicile == exterieur)
                        {
                            nbN++;
                        }
                        else
                            nb2++;

                        if (Math.Abs(domicile - exterieur) == 0)
                        {
                            ecart0++;
                        }
                        else if (Math.Abs(domicile - exterieur) == 1)
                        {
                            ecart1++;
                        }
                        else if (Math.Abs(domicile - exterieur) == 2)
                        {
                            ecart2++;
                        }
                        else if (Math.Abs(domicile - exterieur) == 3)
                        {
                            ecart3++;
                        }
                        else if (Math.Abs(domicile - exterieur) == 4)
                        {
                            ecart4++;
                        }
                        else
                        {
                            ecart5Plus++;
                        }
                    }
                }

                // Cotes 1, N et 2
                if (nb1 == 0) nb1 = -1;
                if (nb2 == 0) nb2 = -1;
                if (nbN == 0) nbN = -1;

                listeMatchs[compteurMatchs].Value[0] = Math.Round(nbScores / nb1, 2, MidpointRounding.AwayFromZero);
                listeMatchs[compteurMatchs].Value[1] = Math.Round(nbScores / nb2, 2, MidpointRounding.AwayFromZero);
                listeMatchs[compteurMatchs].Value[2] = Math.Round(nbScores / nbN, 2, MidpointRounding.AwayFromZero);

                // Pour chaque pronostiqueur
                for (int i = 0; i < scores.Length; i++)
                {
                    var participant = joueurs[i].nom;
                    pointsJoueurActu = 0;
                    gainBrut = 0;

                    domicile = Convert.ToInt32(scores[i].Split('.')[0]);
                    exterieur = Convert.ToInt32(scores[i].Split('.')[1]);

                    if (domicile > -1)
                    {
                        // Si résultats, calcul des points
                        var resultat = resultatsMatchs[compteurMatchs];
                        // Match joué
                        if (resultat.Value[0] > -1)
                        {
                            // Attributions des points
                            if (DonnerResultat(domicile, exterieur) == DonnerResultat(resultat.Value[0], resultat.Value[1]) && EstScoreExact(resultat.Value[0], resultat.Value[1], domicile, exterieur))
                                pointsJoueurActu += 3;
                            else if (DonnerResultat(domicile, exterieur) == DonnerResultat(resultat.Value[0], resultat.Value[1]))
                                pointsJoueurActu += 2;

                            // Attribution des gains
                            if (pointsJoueurActu > 0)
                            {
                                if (resultat.Value[0] > resultat.Value[1]) gainBrut = listeMatchs[compteurMatchs].Value[0];
                                else if (resultat.Value[0] < resultat.Value[1]) gainBrut = listeMatchs[compteurMatchs].Value[1];
                                else gainBrut = listeMatchs[compteurMatchs].Value[2];

                                if (pointsJoueurActu == 3)
                                    gainBrut = gainBrut * 2;
                            }
                        }

                        // Alimentation de la fiche pronostiqueur                        
                        var fiche = new double[2];
                        fiche[0] = pointsJoueurActu;
                        fiche[1] = gainBrut;
                        ficheResultatsJoueurs.Add(new KeyValuePair<string, double[]>(participant, fiche));
                    }
                    // Match non pronostiqué
                    else
                    {
                        var fiche = new double[2];
                        fiche[0] = -1;
                        fiche[1] = -1;
                        ficheResultatsJoueurs.Add(new KeyValuePair<string, double[]>(participant, fiche));
                    }
                }

                //// Calcul des points pour les bots
                //var listeBots = new string[3] { "z_ZZ", "z_UZ", "z_ZU" };

                //for (int i = 0; i < listeBots.Length; i++)
                //{
                //    pointsJoueurActu = 0;
                //    gainBrut = 0;

                //    if (i == 0)
                //    {
                //        domicile = 0;
                //        exterieur = 0;
                //    }
                //    else if (i == 1)
                //    {
                //        domicile = 1;
                //        exterieur = 0;
                //    }
                //    else
                //    {
                //        domicile = 0;
                //        exterieur = 1;
                //    }

                //    // Si résultats, calcul des points
                //    var resultat = resultatsMatchs[compteurMatchs];
                //    // Match joué
                //    if (resultat.Value[0] > -1)
                //    {
                //        // Attributions des points
                //        if (DonnerResultat(domicile, exterieur) == DonnerResultat(resultat.Value[0], resultat.Value[1]) && EstScoreExact(resultat.Value[0], resultat.Value[1], domicile, exterieur))
                //            pointsJoueurActu += 3;
                //        else if (DonnerResultat(domicile, exterieur) == DonnerResultat(resultat.Value[0], resultat.Value[1]))
                //            pointsJoueurActu += 2;
                //    }

                //    // Alimentation de la fiche pronostiqueur                        
                //    var ficheBots = new double[2];
                //    ficheBots[0] = pointsJoueurActu;
                //    ficheBots[1] = 0;
                //    ficheResultatsJoueurs.Add(new KeyValuePair<string, double[]>(listeBots[i], ficheBots));
                //}

                compteurMatchs++;
            }

            // Analyse des données pour le match
            compteurMatchs = 0;

            logPronos.WriteLine("*** CALCUL DES COTES DES MATCHS JOURNEE ***");
            logPronos.WriteLine("");

            for (int i = 0; i < listeMatchs.Count; i++)
            {
                logPronos.WriteLine("Cotes du match " + listeMatchs[i].Key + " (1, N, 2) : " +
                    CoteToString(listeMatchs[i].Value[0]) + ", " +
                    CoteToString(listeMatchs[i].Value[2]) + ", " +
                    CoteToString(listeMatchs[i].Value[1]));
            }

            // Si résultats, rapport des points et des gains
            if (existeResultats)
            {
                var pourClassement = new Dictionary<string, double[]>();

                logPronos.WriteLine("------------------------------------");
                logPronos.WriteLine("*** RESULTATS DES PRONOSTICS JOURNEE ***");
                logPronos.WriteLine("");

                for (int i = 0; i < joueurs.Count; i++)
                {
                    string nomEnCours = ficheResultatsJoueurs[i].Key;
                    double totalPointsJoueur = 0;
                    double totalGainsNetJoueur = 0;

                    var ficheJoueurActu = ficheResultatsJoueurs.Where(x => x.Key == nomEnCours);
                    foreach (var fiche in ficheJoueurActu)
                    {
                        totalPointsJoueur += fiche.Value[0];
                        totalGainsNetJoueur += fiche.Value[1] - 1;
                    }
                    pourClassement.Add(nomEnCours, new double[2] { totalPointsJoueur, totalGainsNetJoueur });

                    if (totalPointsJoueur > -10)
                        logPronos.WriteLine(nomEnCours + " : Points : " + totalPointsJoueur.ToString() + " | Gains net : " + totalGainsNetJoueur.ToString());
                    else
                        logPronos.WriteLine(nomEnCours + " : n'a pas joué.");
                }

                // Classement par points
                logPronos.WriteLine("------------------------------------");
                logPronos.WriteLine("*** CLASSEMENT DES PRONOSTICS JOURNEE ***");
                logPronos.WriteLine("");

                var triParPoints = from pair in pourClassement
                                   orderby pair.Value[0] descending
                                   select pair;
                int cont = 1;
                foreach (var item in triParPoints)
                {
                    if (item.Value[0] > -10)
                        logPronos.WriteLine(cont.ToString() + " - " + item.Key + " : Points : " + item.Value[0].ToString());
                    else
                        logPronos.WriteLine(cont.ToString() + " - " + item.Key + " : n'a pas joué");
                    cont++;
                }

                // Classement par points
                logPronos.WriteLine("------------------------------------");
                logPronos.WriteLine("*** CLASSEMENT DES GAINS JOURNEE ***");
                logPronos.WriteLine("");

                var triParGains = from pair in pourClassement
                                  orderby pair.Value[1] descending
                                  select pair;
                cont = 1;
                foreach (var item in triParGains)
                {
                    if (!item.Key.Contains("z_"))
                    {
                        if (item.Value[0] > -10)
                            logPronos.WriteLine(cont.ToString() + " - " + item.Key + " : Gains : " + item.Value[1].ToString());
                        else
                            logPronos.WriteLine(cont.ToString() + " - " + item.Key + " : n'a pas joué");
                        cont++;
                    }
                }

                // Records
                var fichesSansBots = (from fiche in ficheResultatsJoueurs
                                      orderby fiche.Key descending
                                      select fiche).SkipWhile(x => x.Key.Contains("z_"));

                //var plusGrosGainSur1Match = fichesSansBots.Where(x => x.Value[1] == fichesSansBots.Max(y => y.Value[1]));
                var top3GainsSur1Match = (from fiche in fichesSansBots
                                          orderby fiche.Value[1] descending
                                          select fiche).Take(3);

                //var plusPetitGainSur1Match = (from fiche in fichesSansBots
                //                              where fiche.Value[1] > 0
                //                              select fiche);
                //var test = plusPetitGainSur1Match.Where(x => x.Value[1] == plusPetitGainSur1Match.Min(y => y.Value[1]));

                logPronos.WriteLine("------------------------------------");
                logPronos.WriteLine("Top 3 gains sur un match");

                foreach (var item in top3GainsSur1Match)
                {
                    logPronos.WriteLine(top3GainsSur1Match.ToList().IndexOf(item) + 1 + " : " + item.Key + " ( " + item.Value[1] + " )");
                }

                //if (plusGrosGainSur1Match.Count() == 1)
                //    logPronos.WriteLine("Plus gros gain brut sur un match : " + plusGrosGainSur1Match.First().Key + " ( " + plusGrosGainSur1Match.First().Value[1] + " )");
                //else if (plusGrosGainSur1Match.Count() > 1)
                //{
                //    foreach (var item in plusGrosGainSur1Match)
                //    {
                //        logPronos.WriteLine("Plus gros gain brut sur un match : " + item.Key + " ( " + item.Value[1] + " )");
                //    }
                //}

                //if (test.Count() == 1)
                //    logPronos.WriteLine("Plus petit gain brut sur un match : " + test.First().Key + " ( " + test.First().Value[1] + " )");
                //else if (test.Count() > 1)
                //{
                //    foreach (var item in test)
                //    {
                //        logPronos.WriteLine("Plus petit gain brut sur un match : " + item.Key + " ( " + item.Value[1] + " )");
                //    }
                //}
            }

            pronosJournee.Close();
            matchs.Close();
            resultats.Close();
            logPronos.Close();
        }

        private string CoteToString(double uneCote)
        {
            if (uneCote < 1) return "Aucun prono";
            else return uneCote.ToString();
        }

        private string DonnerResultat(double domicile, double exterieur)
        {
            if (domicile > exterieur) return "1";
            else if (domicile == exterieur) return "N";
            else return "2";
        }

        private bool EstScoreExact(double dom, double ext, double pronoDom, double pronoExt)
        {
            return (dom == pronoDom && ext == pronoExt);
        }
    }
}
